package jinyilw.swing.rlaf.ui;

import jinyilw.common.OSTools;
import jinyilw.common.Operator;
import jinyilw.swing.Alignment;
import jinyilw.swing.NativeTools;
import jinyilw.swing.ScreenTools;
import jinyilw.swing.i18n.ICSetting;
import jinyilw.swing.icon.LazyCustomIcon;
import jinyilw.swing.rlaf.theme.UIData;
import jinyilw.swing.rlaf.utils.RLafUtils;
import jinyilw.swing.visuals.comp.ActIconComp;
import jinyilw.swing.visuals.comp.RichTitleComp;
import jinyilw.swing.visuals.comp.ScaleImageComp;
import jinyilw.swing.visuals.comp.SwitchIconComp;
import jinyilw.swing.visuals.panel.FlowPanel;

import javax.swing.JRootPane;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dialog;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Frame;
import java.awt.LayoutManager;
import java.awt.Rectangle;
import java.awt.Window;
import java.awt.event.WindowEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.util.ArrayList;

/**
 * @author Jinyi
 */
public class RTitlePane extends Container
{
	private static final long serialVersionUID = -5812373303829239481L;

	private FlowPanel actionPanel;
	protected ActIconComp iconifyButton;
	protected SwitchIconComp maxButton;
	protected ActIconComp closeButton;

	protected Component symbol;
	private ScaleImageComp imageLogo;
	Operator<File> changeLogoOperator;
	protected RichTitleComp titleLabel;
	protected int titleHeight;
	protected Font titleFont;
	protected Color titleColor;
	protected Alignment titleAlign = Alignment.CENTER;

	protected PropertyChangeListener propertyChangeListener;
	protected Window window;
	protected JRootPane rootPane;
	protected RRootPaneUI rootPaneUI;

	protected Dimension preferredDimension;
	protected int state = -1;
	protected boolean wasNotified;
	protected boolean wasMaximized;
	protected Rectangle normalBounds;

	protected boolean cancelClosing;
	ArrayList<Operator<?>> beforeClosingOperators;
	ArrayList<Operator<?>> closingOperators;

	public RTitlePane(JRootPane root, RRootPaneUI ui)
	{
		rootPane = root;
		rootPaneUI = ui;
		installSubcomponents();
		setLayout(createLayout());
		window = rootPaneUI.getWindow();
		installListeners();
	}

	protected void installListeners()
	{
		if (window != null)
		{
			if (propertyChangeListener == null)
				propertyChangeListener = createWindowPropertyChangeListener();
			window.addPropertyChangeListener(propertyChangeListener);
		}
	}

	protected void uninstallListeners()
	{
		if (window != null)
			window.removePropertyChangeListener(propertyChangeListener);
	}

	protected PropertyChangeListener createWindowPropertyChangeListener()
	{
		return new WindowPropertyChangeListener();
	}

	public JRootPane getRootPane()
	{
		return rootPane;
	}

	@Override
	public Dimension getPreferredSize()
	{
		return preferredDimension;
	}

	public void setTitle(String text)
	{
		if (text == null)
			return;
		if (text.equals(titleLabel.getText()))
			return;
		titleLabel.setText(null);
		titleLabel.updateText(text);
		if (isShowing())
		{
			revalidate();
			repaint();
		}
	}

	public void setTitle(ICSetting iSetting)
	{
		titleLabel.setText(iSetting);
		if (isShowing())
		{
			revalidate();
			repaint();
		}
	}

	public void setTitle(ICSetting iSetting, boolean zooOutEn)
	{
		titleLabel.setText(iSetting, zooOutEn);
		if (isShowing())
		{
			revalidate();
			repaint();
		}
	}

	public void setTitleColor(Color color)
	{
		if (color == null || titleColor.equals(color))
			return;
		titleColor = color;
		titleLabel.setForeground(color);
	}

	public void setTitleFont(Font font)
	{
		if (font == null || font.equals(titleFont))
			return;
		titleFont = font;
		titleLabel.setFont(font);
	}

	public void setTitleHeight(int height)
	{
		if (titleHeight == height || height < 0)
			return;
		titleHeight = height;
		preferredDimension = new Dimension(titleHeight, titleHeight);
	}

	public void setSymbol(Component symbol)
	{
		Component oldSymbol = this.symbol;
		if ((oldSymbol == null && symbol == null)
				|| (oldSymbol != null && oldSymbol.equals(symbol)))
			return;
		if (oldSymbol != null)
			remove(oldSymbol);
		if (symbol != null)
			add(symbol);
		if (isShowing())
			doLayout();
		this.symbol = symbol;
		if (symbol instanceof ScaleImageComp)
		{
			imageLogo = (ScaleImageComp) symbol;
			imageLogo.addClickOperator(o -> {
				File pngFile = NativeTools.chooseNativeFile(imageLogo, "更换软件图标", "png");
				if (pngFile != null)
				{
					imageLogo.setImage(new LazyCustomIcon(pngFile, 25, 25));
					if (changeLogoOperator != null)
						changeLogoOperator.operate(pngFile);
				}
			});
		}
	}

	public void setChangeLogoOperator(Operator<File> operator)
	{
		changeLogoOperator = operator;
	}

	public void addActionComponent(Component comp)
	{
		if (actionPanel != null)
			actionPanel.add(comp);
	}

	public void cancelClosing()
	{
		cancelClosing = true;
	}

	public void addClosingOperator(Operator<?> operator)
	{
		if (closingOperators == null)
			closingOperators = new ArrayList<>();
		closingOperators.add(operator);
	}

	public void addBeforeClosingOperator(Operator<?> operator)
	{
		if (beforeClosingOperators == null)
			beforeClosingOperators = new ArrayList<>();
		beforeClosingOperators.add(operator);
	}

	public void addHideOperator(Operator<Object> operator)
	{
		if (iconifyButton != null)
			iconifyButton.addClickOperator(operator);
	}

	public int getTitleHeight()
	{
		return titleHeight;
	}

	public void initTitle()
	{
		titleLabel.updateText(getTitle());
	}

	protected Frame getFrame()
	{
		if (window instanceof Frame)
			return (Frame) window;
		return null;
	}

	@Override
	public void addNotify()
	{
		super.addNotify();
		wasNotified = true;
		Window w = rootPaneUI.getWindow();
		if (w == null)
			return;

		if (w != window)
		{
			uninstallListeners();
			window = w;
			initTitle();
			installListeners();
		}
		if (window instanceof Frame)
		{
			setState(((Frame) window).getExtendedState());
		} else
			setState(0);
		setActive(window.isActive());
	}


	private void installSubcomponents()
	{
		actionPanel = new FlowPanel(
				/* (OSSpecificTools.isMac()) ? Alignment.LEFT : Alignment.RIGHT */);
		UIData uiData = UIData.getDefaultUIData();
		if (rootPane.getWindowDecorationStyle() == RRootPaneUI.FRAME)
		{
			closeButton = new ActIconComp(uiData.frameUI.closeIcon,
					uiData.frameUI.closeIcon1);
			iconifyButton = new ActIconComp(uiData.frameUI.hideIcon,
					uiData.frameUI.hideIcon1);
			maxButton = new SwitchIconComp(uiData.frameUI.maxIcon,
					uiData.frameUI.maxIcon1, uiData.frameUI.maxIcon2,
					uiData.frameUI.maxIcon3);

			iconifyButton.addClickOperator(o -> iconify());
			maxButton.addTurnOnOperators(o -> maximize());
			maxButton.addTurnOffOperators(o -> restore());
			titleHeight = uiData.frameUI.titleHeight;
			titleFont = uiData.frameUI.titleFont;
			titleColor = uiData.frameUI.titleColor;

			actionPanel.add(closeButton);
			actionPanel.add(maxButton);
			actionPanel.add(iconifyButton);
			RLafUtils.configSettingMenu(actionPanel);
		} else if (rootPane.getWindowDecorationStyle() != RRootPaneUI.NONE)
		{
			closeButton = new ActIconComp(uiData.dialogUI.closeIcon,
					uiData.dialogUI.closeIcon1);
			titleHeight = uiData.dialogUI.titleHeight;
			titleFont = uiData.dialogUI.titleFont;
			titleColor = uiData.dialogUI.titleColor;
			actionPanel.add(closeButton);
		}
		closeButton.addClickOperator(o -> close());
		titleLabel = new RichTitleComp(getTitle(), titleFont, titleColor);
		add(actionPanel);
		add(titleLabel);
		titleHeight = Math.max(titleHeight, closeButton.getHeight() + 4);
		preferredDimension = new Dimension(titleHeight, titleHeight);
	}

	void updateComponents(boolean resizable)
	{
		if (resizable)
		{
			if (maxButton.getParent() == null)
				actionPanel.add(maxButton, 1);
		} else
		{
			if (maxButton.getParent() != null)
				actionPanel.remove(maxButton);
		}
		actionPanel.doLayout();
	}

	public LayoutManager createLayout()
	{
		return new TitlePaneLayout();
	}

	public void iconify()
	{
		Frame frame = getFrame();
		if (frame != null)
		{
			frame.setExtendedState(Frame.ICONIFIED);
		}
	}

	public void maximize()
	{
		if (window != null && !wasMaximized)
		{
			wasMaximized = true;
			normalBounds = window.getBounds();
			window.setBounds(ScreenTools.getDefaultScreenUsableBounds());
			if (maxButton != null)
				maxButton.turnOn();
		}
	}

	public void restore()
	{
		if (window != null && wasMaximized)
		{
			wasMaximized = false;
			window.setBounds(normalBounds);
			if (maxButton != null)
				maxButton.turnOff();
		}
	}

	public void close()
	{
		if (beforeClosingOperators != null)
			for (Operator<?> operator : beforeClosingOperators)
				operator.run();
		if (cancelClosing)
		{
			cancelClosing = false;
			return;
		}
		if (closingOperators != null)
			for (Operator<?> operator : closingOperators)
				operator.run();
		if (window != null)
			window.dispatchEvent(
					new WindowEvent(window, WindowEvent.WINDOW_CLOSING));
	}

	public boolean wasMaximized()
	{
		return wasMaximized;
	}

	protected void setActive(boolean flag)
	{
	}

	protected boolean isActive()
	{
		return window != null && window.isActive();
	}

	protected boolean isLeftToRight()
	{
		return (window == null)
				? getRootPane().getComponentOrientation().isLeftToRight()
				: window.getComponentOrientation().isLeftToRight();
	}

	protected void setState(int state)
	{
		setState(state, false);
	}

	protected void setState(int state, boolean updateRegardless)
	{
		if (this.state == state && !updateRegardless)
			return;
		if (window == null
				|| rootPane.getWindowDecorationStyle() != RRootPaneUI.FRAME)
			return;

		Frame frame = getFrame();
		if (frame != null)
		{
			updateComponents(frame.isResizable());
		} else
		{
			actionPanel.remove(maxButton);
			actionPanel.remove(iconifyButton);
			actionPanel.repaint();
		}
		this.state = state;
	}

	protected String getTitle()
	{
		String title = null;
		window = rootPaneUI.getWindow();
		if (window instanceof Frame)
			title = ((Frame) window).getTitle();
		else if (window instanceof Dialog)
			title = ((Dialog) window).getTitle();
		return title;
	}

	protected class TitlePaneLayout implements LayoutManager
	{
		@Override
		public void addLayoutComponent(String name, Component c)
		{
		}

		@Override
		public void removeLayoutComponent(Component c)
		{
		}

		@Override
		public Dimension preferredLayoutSize(Container c)
		{
			return new Dimension(titleHeight, titleHeight);
		}

		@Override
		public Dimension minimumLayoutSize(Container c)
		{
			return preferredLayoutSize(c);
		}

		@Override
		public void layoutContainer(Container c)
		{
			int width = getWidth(), height = getHeight();
			if (actionPanel != null)
			{
				// if (OSSpecificTools.isMac())
				// actionPanel.setLocation(1, 0);
				// else
				actionPanel.setLocation(width - actionPanel.getWidth() - 1, 0);
			}
			if (titleLabel != null)
			{
				if (titleAlign == Alignment.CENTER)
				{
					titleLabel.setLocation((width - titleLabel.getWidth()) / 2,
							(height - titleLabel.getHeight()) / 2);
				} else
				{
					int x = symbol != null ? symbol.getWidth() + 5 : 5;
					titleLabel.setLocation(x,
							(height - titleLabel.getHeight()) / 2);
				}
			}
			if (symbol != null)
				symbol.setLocation(3, (height - symbol.getHeight()) / 2);
		}
	}

	protected class WindowPropertyChangeListener
			implements
			PropertyChangeListener
	{
		@Override
		public void propertyChange(PropertyChangeEvent pce)
		{
			String name = pce.getPropertyName();
			if ("resizable".equals(name) || "state".equals(name))
			{
				if (!wasNotified)
					return;
				Frame frame = getFrame();
				if (frame != null)
					setState(frame.getExtendedState(), true);
				if ("resizable".equals(name))
					rootPane.repaint();
			} else if ("title".equals(name))
			{
				setTitle(getTitle());
			} else if ("componentOrientation".equals(name))
			{
				if (!wasNotified)
					return;
				revalidate();
				repaint();
			} else if ("iconImage".equals(name))
			{
				Frame frame = getFrame();
				if (frame != null && OSTools.isMac())
					NativeTools.setMacDockImage(frame.getIconImage());
			}
		}
	}
}
